package com.dc.docs._888_面试.concurrent._1_volatile;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Description: 测试 Volatile关键词不保证原子性_解决方案_锁机制
 * @author: gdc
 * @date: 2021/6/15
 * @version 1.0
 */
public class Volatile_5_Lock {

    /**
     * 被 volatile修饰
     */
    private volatile int number = 0;
    private Lock lock = new ReentrantLock();

    /**
     * 累加操作, 此处对操作方法进行加锁处理1，使用 synchronized 解决
     */
    public synchronized void increase(){
        number++;
    }

    /**
     * 累加操作, 此处对操作方法进行加锁处理2，使用 ReentrantLock 解决
     * (需要将声明的锁放到外面去，这样才能保证，进来的线程，始终使用的是同一把锁)
     */
    public void increase2(){
        lock.lock();
        try {
            number++;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args){
        Volatile_5_Lock volatileDemo = new Volatile_5_Lock();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    //volatileDemo.increase();
                    volatileDemo.increase2();
                }
            }, "AAA").start();
        }

        // 默认有main线程和gc线程
        while (Thread.activeCount() > 2) {
            // 使当前线程由执行状态变为就绪状态，让出cpu时间，在下一个线程执行时候，此线程有可能被执行，也有可能没有被执行
            Thread.yield();
        }

        // 测试最终累加的结果：20 * 1000 = 20000，由于没法保证原子性，所以最终的结果无法达到
        System.out.println(Thread.currentThread().getName() + " finally number value:" + volatileDemo.number);
    }
}
